调试总结

您所在的位置:网站首页 stc iic从机 调试总结

调试总结

2024-06-04 10:07| 来源: 网络整理| 查看: 265

以前玩IIC都是停留在EEPROM里,知道协议的流程,但是一旦使用的时候总是会忘记,理解的不够透彻。今天在做两块MCU的IIC通讯的时候,写个调试总结。

1.两个MCU通讯的理解

借用EEPROM的IIC时序图: 在这里插入图片描述 在这里插入图片描述 这两个时序只能说很有代表性,在两个MCU通讯的时候也可以借鉴这个时序图。 以下是本次的协议图: 在这里插入图片描述

把其中一个单片机设置为从机,一个单片机设置为主机,简单的通讯的话,不需要翻转两者的主从关系。也就是把第一个单片机当做EEPROM用 2.如何编写及调试 (1)编写主机MCU

直接按照普通IIC配置初始化,有的单片机是必须要配置成master mode。这时初始化配置slave 地址,即使配置了也是无效的。 主机调试注意点:

①IIC写函数中,最好要用示波器抓写的波形,千万要仔细对着时序图,查看高低电平,什么时候应该是什么电平要对比好,我就是在找没有ack回复问题的时候,才发现,起始SCL和SDA居然是低电平 ②从机的地址要配置好,有的写函数中调用的地址是偏移过以为的地址,有的则不是,所以我们要确认好我们从机配置的地址,注意:7位(我用的)的地址,我总把描述8位从机地址当做未偏移的从机地址,实际上只有高7位才是实际地址,最后一个是读写位。 ③在IIC读写函数中,实际有很多的状态,我们可以的在不同状态下处理一些函数,比如华大的IIC发送函数,其中获取到的u8State都代表了不同状态,这个在数据手册是有描述的。 en_result_t I2C_MasterWriteData(M0P_I2C_TypeDef* I2CX,uint8_t *pu8Data,uint32_t u32Len,uint32_t Slave_addr) { en_result_t enRet = Error; uint8_t u8i=0,u8State; I2C_SetFunc(I2CX,I2cStart_En); while(1) { while(0 == I2C_GetIrq(I2CX)) {;} u8State = I2C_GetState(I2CX); //printf("u8State = %x\n",u8State); switch(u8State) { //step1: case 0x08: ///已发送起始条件 I2C_ClearFunc(I2CX,I2cStart_En); I2C_WriteByte(I2CX,Slave_addr); ///从设备地址发送 break; //step2: case 0x18: ///已发送SLA+W,并接收到ACK //step3: //printf("ack\n"); case 0x28: ///上一次发送数据后接收到ACK I2C_WriteByte(I2CX,pu8Data[u8i++]); break; case 0x20: ///上一次发送SLA+W后,收到NACK case 0x38: ///上一次在SLA+读或写时丢失仲裁 I2C_SetFunc(I2CX,I2cStart_En); ///当I2C总线空闲时发送起始条件 break; case 0x30: ///已发送I2Cx_DATA中的数据,收到NACK,将传输一个STOP条件 I2C_SetFunc(I2CX,I2cStop_En); ///发送停止条件 break; default: break; } if(u8i>u32Len) { I2C_SetFunc(I2CX,I2cStop_En); ///此顺序不能调换,出停止条件 I2C_ClearIrq(I2CX); break; } I2C_ClearIrq(I2CX); ///清除中断状态标志位 } enRet = Ok; return enRet; } en_result_t I2C_MasterReadData(M0P_I2C_TypeDef* I2CX,uint8_t *pu8Data,uint32_t u32Len,uint32_t Slave_addr) { en_result_t enRet = Error; uint8_t u8i=0,u8State; I2C_SetFunc(I2CX,I2cStart_En); while(1) // { while((0 == I2C_GetIrq(I2CX)) {} //----------------- u8State = I2C_GetState(I2CX); switch(u8State) { case 0x08: //已发送起始条件,将发送SLA+R I2C_ClearFunc(I2CX,I2cStart_En); I2C_WriteByte(I2CX,Slave_addr);//发送SLA+W break; case 0x18: //已发送SLA+W,并接收到ACK // I2C_WriteByte(I2CX,0); //发送内存地址 // I2C_SetFunc(I2CX,I2cStop_En); I2C_SetFunc(I2CX,I2cStart_En); break; case 0x28: //已发送数据,接收到ACK //I2C_SetFunc(I2CX,I2cStart_En); break; case 0x10: //已发送重复起始条件 I2C_ClearFunc(I2CX,I2cStart_En); I2C_WriteByte(I2CX,Slave_addr|0x01);//读命令发送 break; case 0x40: //已发送SLA+R,并接收到ACK if(u32Len>1) { I2C_SetFunc(I2CX,I2cAck_En); } break; case 0x50: //已接收数据字节,并已返回ACK信号 pu8Data[u8i++] = I2C_ReadByte(I2CX); if(u8i==u32Len-1) { I2C_ClearFunc(I2CX,I2cAck_En); //读数据时,倒数第二个字节ACK关闭 } break; case 0x58: //已接收到最后一个数据,NACK已返回 pu8Data[u8i++] = I2C_ReadByte(I2CX); I2C_SetFunc(I2CX,I2cStop_En); //发送停止条件 break; case 0x38: //在发送地址或数据时,仲裁丢失 I2C_SetFunc(I2CX,I2cStart_En); //当总线空闲时发起起始条件 break; case 0x48: //发送SLA+R后,收到一个NACK I2C_SetFunc(I2CX,I2cStop_En); I2C_SetFunc(I2CX,I2cStart_En); break; default: //其他错误状态,重新发送起始条件 I2C_SetFunc(I2CX,I2cStart_En); //其他错误状态,重新发送起始条件 break; } I2C_ClearIrq(I2CX); //清除中断状态标志位 if(u8i==u32Len) //数据全部读取完成,跳出while循环 { break; } } enRet = Ok; return enRet; } (2)编写从机MCU

从机MCU需要配置好从机地址,如果主机是写指令,初始化配置好后,一般会自动回复ACK。 但是数据的读取是需要从机发送的,什么时候发送数据,这个沟通的协议就要从机来进行配置。

从机调试注意点:

①如果是硬件的IIC,初始化ENABLE ACK会自动回复ACK ②从机配置是两个MCU协议最重要的地方,读写的协议都是根据从设备的配置来设定的。从设备主要是接收,只有在主设备读数据的时候,从设备才会调用发送函数,比如GD作为从机的中断函数: void I2C0_EventIRQ_Handler(void) { if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND)) //成功接受到了主设备发过来的地址 { /* clear the ADDSEND bit */ i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND); I2C_rxbytes = 0; if(SUCCESS == rx_success) //第二次收到地址讯息,代表主设备要来读数据了 { restart_num++; send_ok = 0; //if(restart_num == 2) //{ //nvic_irq_disable(I2C0_EV_IRQn); //} } else { restart_num = 0; } iic_count = 0; } else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE)) //主设备写数据,这边接收发过来的数据 { restart_num = 0; /* if reception data register is not empty ,I2C0 will read a data from I2C_DATA */ i2c_rxbuffer[I2C_rxbytes++] = i2c_data_receive(I2C0); I2C_rxbytes = I2C_rxbytes;//%I2C_nBytes; } else if((i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE))&&(iic_count rx_success = 0; /* send a data byte */ i2c_data_transmit(I2C0, i2c_txbuffer[iic_count++]); //主设备读取,从设备发送数据的地方 } } else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_STPDET))//获取到停止信号的中断 { rx_end = SUCCESS; rx_success = SUCCESS; restart_num = 0; / //I2C_txbytes = 0; //i2c_txbuffer = (void *)0; / /* clear the STPDET bit */ i2c_enable(I2C0); }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3